package com.joker.aigc.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alicp.jetcache.Cache;
import com.alicp.jetcache.CacheManager;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.template.QuickConfig;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.joker.aigc.domain.dto.UserDto;
import com.joker.aigc.domain.dto.UserQueryCriteria;

import com.joker.aigc.domain.entity.User;
import com.joker.aigc.domain.enums.WebSocketChatActiveStatusEnum;
import com.joker.aigc.domain.mapstruct.UserMapstruct;
import com.joker.aigc.domain.vo.UserVo;
import com.joker.aigc.mapper.UserMapper;
import com.joker.aigc.service.UserService;
import com.joker.aigc.utils.RedisKey;
//import com.joker.aigc.utils.RedisUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author 20346
 * @description 针对表【user】的数据库操作Service实现
 * @createDate 2023-12-17 11:26:08
 */
@Slf4j
@Transactional
@RequiredArgsConstructor
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final CacheManager cacheManager;
    /**
     * 在线的
     */
    private Cache<String, List<Long>> userOnlineCache;

    @PostConstruct
    public void init() {
        QuickConfig qc = QuickConfig.newBuilder("userOnlineCache:")
                .expire(Duration.ofSeconds(36000))
                .cacheType(CacheType.LOCAL)
                // 本地缓存更新后，将在所有的节点中删除缓存，以保持强一致性
                .syncLocal(false)
                .build();
        userOnlineCache = cacheManager.getOrCreateCache(qc);
    }

    /**
     * 用户类型转换器
     */
    final UserMapstruct userMapstruct;
    /**
     * 用户密码 加密解密工具类
     */
    final PasswordEncoder passwordEncoder;


    /**
     * 判断用户是否在线
     *
     * @param uid 用户id
     * @return 返回是否在线
     */
    @Override
    public Boolean isOnline(Long uid) {
        // 判断用户是否在线
        User user = getById(uid);
        return user != null && WebSocketChatActiveStatusEnum.ONLINE.getStatus().equals(user.getActiveStatus());
    }

    public QueryWrapper<User> getQuery(UserQueryCriteria criteria) {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.lambda().eq(criteria.getUid() != null, User::getId, criteria.getUid());
        return userQueryWrapper;
    }

    @Override
    public Page<UserVo> queryAll(UserQueryCriteria userQueryCriteria) {
        // 用来返回所有用户信息，便于测试
        Page<User> page = page(
                new Page<>(userQueryCriteria.getPageNum(), userQueryCriteria.getPageSize()),
                getQuery(userQueryCriteria)
        );
        Page<UserVo> voPage = new Page<>(userQueryCriteria.getPageNum(), userQueryCriteria.getPageSize(), page.getTotal());
        List<UserVo> userVoList = userMapstruct.toVO(page.getRecords());
        voPage.setRecords(userVoList);
        log.info("user queryAll-->{}", voPage);
        return voPage;
    }


    @Override
    public void updateUser(UserDto userDto) {

    }

    @Override
    public void deleteUser(Long uid) {

    }

    @Override
    public UserVo queryById(Long uid) {
        User user = getById(uid);
        return userMapstruct.toVO(user);
    }


    /**
     * 统计在线人数
     *
     * @param memberUidList 整体用户列表
     * @return
     */
    @Override
    public Integer getOnlineCount(List<Long> memberUidList) {
        // 首先是状态
        return Math.toIntExact(lambdaQuery()
                .eq(User::getActiveStatus, WebSocketChatActiveStatusEnum.ONLINE.getStatus())
                .in(CollUtil.isNotEmpty(memberUidList), User::getId, memberUidList)
                .count());
    }

    @Override
    public Integer getOnlineNum() {
        String onlineKey = RedisKey.getKey(RedisKey.ONLINE_UID_ZET);
        List<Long> longs = userOnlineCache.get(onlineKey);
        if (CollUtil.isNotEmpty(longs)) {
            return longs.size();
        }
        return 0;
    }

    @Override
    //移除用户
    public void removeOnline(Long uid) {
        String onlineKey = RedisKey.getKey(RedisKey.ONLINE_UID_ZET);
        String offlineKey = RedisKey.getKey(RedisKey.OFFLINE_UID_ZET);
        //移除离线表
        remove(offlineKey, uid);
//        RedisUtils.zRemove(offlineKey, uid);
        //移除上线表
        remove(onlineKey, uid);
//        RedisUtils.zRemove(onlineKey, uid);
    }


    public void remove(String key, Long uid) {
        List<Long> longs = userOnlineCache.get(key);
        if (CollUtil.isNotEmpty(longs)) {
            longs.remove(uid);
            userOnlineCache.put(key, longs);
        }
    }


    public void add(String key, Long uid) {
        List<Long> longs = userOnlineCache.get(key);
        if (CollUtil.isEmpty(longs)) {
            longs = new ArrayList<>();
        }
        if (longs.contains(uid)) {
            longs.add(uid);
        }
        userOnlineCache.put(key, longs);
    }

    @Override
    public void offline(Long uid, Date optTime) {
        String onlineKey = RedisKey.getKey(RedisKey.ONLINE_UID_ZET);
        String offlineKey = RedisKey.getKey(RedisKey.OFFLINE_UID_ZET);
        //移除上线线表
        remove(onlineKey, uid);
//        RedisUtils.zRemove(onlineKey, uid);
        //更新上线表
//        RedisUtils.zAdd(offlineKey, uid, optTime.getTime());
    }

    @Override
    public void addOnline(Long uid) {
        // 设置上线人数
        String onlineKey = RedisKey.getKey(RedisKey.ONLINE_UID_ZET);
        String offlineKey = RedisKey.getKey(RedisKey.OFFLINE_UID_ZET);
        //移除离线表
        remove(offlineKey, uid);
//        RedisUtils.zRemove(offlineKey, uid);
        //更新上线表
        add(offlineKey, uid);
//        RedisUtils.zAdd(onlineKey, uid, new Date().getTime());
    }

}




